package com.sniper.web.action;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sniper.data.BaseData;
import com.sniper.data.DataValues;
import com.sniper.exception.DirNotCreateException;
import com.sniper.model.Files;
import com.sniper.web.utils.FilesUtil;
import com.sniper.web.utils.SystemConfigUtil;
import com.sniper.web.utils.UserDetailsUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

@Controller
public class FileUploadController extends RootController {


    /**
     * 文件上传，返回json数据
     *
     * @param imgFile  上传的数据
     * @param locale   语言
     * @param dir      上传的目录
     * @param response
     * @param writer
     * @throws IOException
     */
    // @RequiresPermissions("admin:upload")
    @RequestMapping(value = "upload")
    public void upload(@RequestParam("imgFile") MultipartFile imgFile, Locale locale,
                       @RequestParam(value = "dir", required = false, defaultValue = "image") String dir,
                       HttpServletResponse response, PrintWriter writer) throws IOException {
        Map<String, Object> ajaxResult = new HashMap<>();
        UserDetailsUtils detailsUtils = new UserDetailsUtils();
        if (!detailsUtils.validRole(DataValues.ROLE_ADMIN)) {
            long minFileSizeL = SystemConfigUtil.getLong("minFileSize");
            if (imgFile.getSize() < minFileSizeL) {
                ajaxResult = alert(messageSource.getMessage("fileupload.minsize",
                        new String[]{String.valueOf(minFileSizeL)}, locale));
            }
        }
        // 0表示无限制
        int minImgWidth = 0;

        String rootDir = FilesUtil.getRootDir();
        if (imgFile != null) {
            // 上传文件,获取上传后的地址,这个地址不包含目录前缀
            // 原图地址,也可以理解成大图
            String savePath = uploadFile(imgFile, dir);
            // 缩略图生成检测
            //得多缩略图路径
            String saveThumbUrl = savePath;
            // 返回第一章缩略图的路径
            ajaxResult.put("error", 0);
            // 返回编译器使用,返回缩略图，这个值会根据编辑器的设置而改变
            ajaxResult.put("url", FilesUtil.getImagePrefix() + saveThumbUrl);
            // 返回个人使用
            ajaxResult.put("filePath", FilesUtil.getImagePrefix() + saveThumbUrl);
            ajaxResult.put("fileShotPath", saveThumbUrl);
            ajaxResult.put("fileType", imgFile.getContentType());
            String aid = getSaveFilesID(imgFile, savePath, saveThumbUrl, 100, 100);
            ajaxResult.put("id", aid);
            ajaxResult.put("oldName", imgFile.getOriginalFilename());
        } else {
            ajaxResult = alert(messageSource.getMessage("fileupload.nofile", null, locale));

        }

        String header = request.getHeader("User-Agent");
        if (header.contains("MSIE")) {
            response.setContentType("text/html;charset=UTF-8");
        } else {
            response.setContentType("application/json;charset=UTF-8");
        }
        ObjectMapper json = new ObjectMapper();
        String tempFileValue = json.writeValueAsString(ajaxResult);
        JsonNode jsonNode = json.readTree(tempFileValue);
        writer.print(jsonNode);
    }

    /**
     * 负责保存附件
     *
     * @param imgFile
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     */
    private String uploadFile(MultipartFile imgFile, String dir) {

        String rootDir = FilesUtil.getRootDir();

        // 保存的目录，是固定目录，只能更改rootpath目录移动文件
        String saveFileName = getSaveFilename(imgFile).toLowerCase();
        String savePath = FilesUtil.getSaveDir(dir);

        // 用户前台显示
        String saveUrl = savePath;

        // 组装真的url
        savePath = rootDir + savePath;
        // 检查文件夹是否存在
        File fileDir = new File(savePath);
        if (!fileDir.isDirectory()) {
            boolean mk = fileDir.mkdirs();
            if (!mk) {
                throw new DirNotCreateException("无权限创建目录:" + savePath);
            }
        }
        savePath += saveFileName;
        saveUrl += saveFileName;


        FileOutputStream out = null;
        InputStream in = null;
        try {
            in = imgFile.getInputStream();
            out = new FileOutputStream(savePath);
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }


        return saveUrl;
    }

    /**
     * 生成文件问名称
     *
     * @return
     */
    private String getSaveFilename(MultipartFile imgFile) {
        String fileExt = imgFile.getOriginalFilename().substring(imgFile.getOriginalFilename().lastIndexOf(".") + 1)
                .toLowerCase();
        return FilesUtil.getUUIDName(fileExt, false);
    }

    /**
     * 吧上传的文件保存在数据库
     *
     * @param imgFile
     * @param savePath
     * @param saveThumbPath
     * @return
     */
    private String getSaveFilesID(MultipartFile imgFile, String savePath, String saveThumbPath, int width, int height) {
        Files files = new Files();
        files.setNewPath(saveThumbPath);
        // 发送到图片服务器
        String rootDir = FilesUtil.getRootDir();

        //保存原图地址
        files.setOldName(savePath);
        files.setSize(imgFile.getSize());
        files.setWidth(width);
        files.setHeight(height);

        // 获取后缀
        String suffix = FilesUtil.getFileExt(savePath);
        files.setFileType(imgFile.getContentType());
        files.setSuffix(imgFile.getOriginalFilename().replace("." + suffix, ""));
        UserDetailsUtils detailsUtils = new UserDetailsUtils();
        files.setUid(detailsUtils.getAdminUser().getId());

        try {
            files.setHash(DigestUtils.md5Hex(imgFile.getBytes()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return files.getId();
    }

    // @RequiresPermissions("admin:htmlmanager")
    @SuppressWarnings("unchecked")
    @ResponseBody
    @RequestMapping(value = "htmlmanager")
    public void htmlmanager(@RequestParam(value = "dir", required = false, defaultValue = "image") String dir,
                            @RequestParam(value = "order") String orderSource,
                            @RequestParam(value = "path", required = false) String pathSource, PrintWriter writer) throws IOException {

        String rootDir = FilesUtil.getRootDir();

        // 根目录路径，可以指定绝对路径，比如 /var/www/attached/
        String rootPath = rootDir + "/attachments/";
        // 根目录URL，可以指定绝对路径，比如 http://www.yoursite.com/attached/
        String rootUrl = FilesUtil.getWebUrl(getBasePath()) + "/attachments/";

        // 图片扩展名
        String[] fileTypes = new String[]{"gif", "jpg", "jpeg", "png", "bmp"};

        if (dir != null) {
            if (!Arrays.asList(new String[]{"image", "flash", "media", "file"}).contains(dir)) {
                writer.print("Invalid Directory name.");
            }
            rootPath += dir + "/";
            rootUrl += dir + "/";
            File saveDirFile = new File(rootPath);
            if (!saveDirFile.exists()) {
                saveDirFile.mkdirs();
            }
        }
        // 根据path参数，设置各路径和URL
        String path = pathSource != null ? pathSource : "";
        String currentPath = rootPath + path;
        String currentUrl = rootUrl + path;
        String moveupDirPath = "";
        // 请求的路径
        if (!"".equals(path)) {
            String str = path.substring(0, path.length() - 1);
            moveupDirPath = str.lastIndexOf("/") >= 0 ? str.substring(0, str.lastIndexOf("/") + 1) : "";
        }

        // 排序形式，name or size or type
        String order = orderSource != null ? orderSource.toLowerCase() : "name";

        // 不允许使用..移动到上一级目录
        if (path.contains("..")) {
            writer.print("Access is not allowed.");
            return;
        }

        // 最后一个字符不是/
        if (!"".equals(path) && !path.endsWith("/")) {
            writer.print("Parameter is not valid.");
            return;
        }
        // 目录不存在或不是目录
        File currentPathFile = new File(currentPath);
        if (!currentPathFile.isDirectory()) {
            writer.print("Directory does not exist.");
            return;
        }
        // 遍历目录取的文件信息
        List<Hashtable<String, Object>> fileList = new ArrayList<>();
        File[] files = currentPathFile.listFiles();
        if (files != null && files.length > 0) {
            for (File file : files) {
                Hashtable<String, Object> hash = new Hashtable<>();
                String fileName = file.getName();
                if (file.isDirectory()) {
                    hash.put("is_dir", true);
                    hash.put("has_file", (file.listFiles() != null));
                    hash.put("filesize", 0L);
                    hash.put("is_photo", false);
                    hash.put("filetype", "");
                } else if (file.isFile()) {
                    String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
                    hash.put("is_dir", false);
                    hash.put("has_file", false);
                    hash.put("filesize", file.length());
                    hash.put("is_photo", Arrays.asList(fileTypes).contains(fileExt));
                    hash.put("filetype", fileExt);
                }
                hash.put("filename", fileName);
                hash.put("datetime", new SimpleDateFormat(BaseData.DATE_TIME_FORMAT).format(file.lastModified()));
                fileList.add(hash);
            }
        }

        if ("size".equals(order)) {
            fileList.sort(FileUploadController::SizeCompare);
        } else if ("type".equals(order)) {
            fileList.sort(new TypeComparator());
        } else {
            fileList.sort(new NameComparator());
        }

        Map<String, Object> ajaxResult = new HashMap<>();

        ajaxResult.put("moveup_dir_path", moveupDirPath);
        ajaxResult.put("current_dir_path", path);
        ajaxResult.put("current_url", currentUrl);
        ajaxResult.put("total_count", fileList.size());
        ajaxResult.put("file_list", fileList);

        // 输出结果
        ObjectMapper json = new ObjectMapper();
        String jsonValue = json.writeValueAsString(ajaxResult);
        JsonNode jsonNode = json.readTree(jsonValue);
        writer.print(jsonNode);
    }

    /**
     * 返回错误
     *
     * @param msg
     * @return
     */
    private Map<String, Object> alert(String msg) {
        Map<String, Object> ajaxResult = new HashMap<>();

        ajaxResult.put("error", 1);
        ajaxResult.put("message", msg);
        return ajaxResult;
    }

    /**
     * 下面的写法可以使用java8的写法，函数式接口写
     * 大小排序
     *
     * @param m1
     * @param m2
     * @return
     */
    private static int SizeCompare(Map<String, Object> m1, Map<String, Object> m2) {
        if (((Boolean) m1.get("is_dir")) && !((Boolean) m2.get("is_dir"))) {
            return -1;
        } else if (!((Boolean) m1.get("is_dir")) && ((Boolean) m2.get("is_dir"))) {
            return 1;
        } else {
            if (((Long) m1.get("filesize")) > ((Long) m2.get("filesize"))) {
                return 1;
            } else if (((Long) m1.get("filesize")) < ((Long) m2.get("filesize"))) {
                return -1;
            } else {
                return 0;
            }
        }
    }

    @SuppressWarnings("rawtypes")
    public static class NameComparator implements Comparator {
        @Override
        public int compare(Object a, Object b) {
            Hashtable hashA = (Hashtable) a;
            Hashtable hashB = (Hashtable) b;
            if (((Boolean) hashA.get("is_dir")) && !((Boolean) hashB.get("is_dir"))) {
                return -1;
            } else if (!((Boolean) hashA.get("is_dir")) && ((Boolean) hashB.get("is_dir"))) {
                return 1;
            } else {
                return ((String) hashA.get("filename")).compareTo((String) hashB.get("filename"));
            }
        }
    }


    /**
     * 根据类型排序
     *
     * @author sniper
     */
    public static class TypeComparator implements Comparator<Object> {
        @Override
        public int compare(Object a, Object b) {
            Hashtable<?, ?> hashA = (Hashtable<?, ?>) a;
            Hashtable<?, ?> hashB = (Hashtable<?, ?>) b;
            if (((Boolean) hashA.get("is_dir")) && !((Boolean) hashB.get("is_dir"))) {
                return -1;
            } else if (!((Boolean) hashA.get("is_dir")) && ((Boolean) hashB.get("is_dir"))) {
                return 1;
            } else {
                return ((String) hashA.get("filetype")).compareTo((String) hashB.get("filetype"));
            }
        }
    }

}
